﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Common.Utilities;
using Common.Utilities.DLR;
using Common.Utilities.Documents;
using Rules.Diagram;
using WindowsUserControl.UIUpdateWrapper;
using Workflows.Components.Rules;
using Workflows.Designer.OfficeUtil;
using Microsoft.Office.Interop.Word;
using Northwoods.Go;
using TD.SandDock;
using Application=Microsoft.Office.Interop.Word.Application;
using Rectangle=System.Drawing.Rectangle;
using Rule=Workflows.Components.Rules.Rule;

namespace Workflows.Designer
{
    /// <summary>
    /// UI front end for rule definition
    /// </summary>
    public partial class RuleDesigner : Form, IMainForm
    {
        #region fields
        private bool isBusy;
        private object draggedObject;
        private Dictionary<Guid, TD.SandDock.TabbedDocument> _TabbedDocuments;
        #endregion

        #region init
        /// <summary>
        /// 
        /// </summary>
        public RuleDesigner()
        {
            InitializeComponent();
        }
        
        private void Main_Load(object sender, EventArgs e)
        {
            this._TabbedDocuments = new Dictionary<Guid, TabbedDocument>();
            this.PopulateRules();
            this.PopulateConditionNodes();
            this.PopulateActionNodes();
            this.PopulateEffectNodes();
            this.PopulateOutputNodes();
        }

        private void PopulateConditionNodes()
        {
            List<RuleNodeDataBase> conditions = RuleNodeFactory.GetRuleConditionNodes();
            this.tree_Conditions.Nodes.Clear();
            if(conditions !=null && conditions.Count>0)
            {
                foreach(RuleNodeDataBase condition in conditions)
                {
                    TreeNode conditionTn=new TreeNode(condition.Name);
                    conditionTn.ImageIndex = 12;
                    conditionTn.SelectedImageIndex = 12;
                    RuleNode ruleNode = new RuleNode(condition.RuleNodeType);
                    ruleNode.ToolTipText = condition.Description;
                    ruleNode.UserObject = condition;
                    ruleNode.Image.Image = this.ScaleImageSize(condition.Img);
                    conditionTn.Tag = ruleNode;
                    this.tree_Conditions.Nodes.Add(conditionTn);
                }
            }
        }

        private void PopulateOutputNodes()
        {
            List<RuleNodeDataBase> outputs = RuleNodeFactory.GetRuleOutputNodes();
            this.tree_Outputs.Nodes.Clear();
            if (outputs != null && outputs.Count > 0)
            {
                foreach (RuleNodeDataBase output in outputs)
                {
                    TreeNode outputTn = new TreeNode(output.Name);
                    outputTn.ImageIndex = 2;
                    outputTn.SelectedImageIndex = 2;
                    RuleNode ruleNode = new RuleNode(output.RuleNodeType);
                    ruleNode.ToolTipText = output.Description;
                    ruleNode.UserObject = output;
                    ruleNode.Image.Image = this.ScaleImageSize(output.Img);
                    outputTn.Tag = ruleNode;
                    this.tree_Outputs.Nodes.Add(outputTn);
                }
            }
        }

        private void PopulateEffectNodes()
        {
            List<RuleNodeDataBase> effects = RuleNodeFactory.GetRuleEffectNodes();
            this.tree_Effects.Nodes.Clear();
            if (effects != null && effects.Count > 0)
            {
                foreach (RuleNodeDataBase effect in effects)
                {
                    TreeNode effectTn = new TreeNode(effect.Name);
                    effectTn.ImageIndex = 14;
                    effectTn.SelectedImageIndex = 14;
                    RuleNode ruleNode = new RuleNode(effect.RuleNodeType);
                    ruleNode.ToolTipText = effect.Description;
                    ruleNode.UserObject = effect;
                    ruleNode.Image.Image = this.ScaleImageSize(effect.Img);
                    effectTn.Tag = ruleNode;
                    this.tree_Effects.Nodes.Add(effectTn);
                }
            }
        }

        private void PopulateActionNodes()
        {
            List<RuleNodeDataBase> actions = RuleNodeFactory.GetRuleActionNodes();
            this.tree_Actions.Nodes.Clear();
            if (actions != null && actions.Count > 0)
            {
                foreach (RuleNodeDataBase action in actions)
                {
                    TreeNode actionTn = new TreeNode(action.Name);
                    actionTn.ImageIndex = 15;
                    actionTn.SelectedImageIndex = 15;
                    RuleNode ruleNode = new RuleNode(action.RuleNodeType);
                    ruleNode.ToolTipText = action.Description;
                    ruleNode.UserObject = action;
                    ruleNode.Image.Image = this.ScaleImageSize(action.Img);
                    actionTn.Tag = ruleNode;
                    this.tree_Actions.Nodes.Add(actionTn);
                }
            }
        }

        private void PopulateRules()
        {
            this.tree_Rules.Nodes.Clear();
            try
            {
                ORMapping<Rule> orm = new ORMapping<Rule>();
                string connStr = ConfigurationManager.ConnectionStrings["Workflow"].ConnectionString;
                List<Rule> rules = orm.GetAll(connStr);
                if (rules != null && rules.Count > 0)
                {
                    foreach (Rule rule in rules)
                    {
                        TreeNode ruleTn = new TreeNode(rule.RuleName);
                        ruleTn.ImageIndex = 1;
                        ruleTn.SelectedImageIndex = 1;
                        ruleTn.Tag = rule;
                        this.tree_Rules.Nodes.Add(ruleTn);
                    }
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private Image ScaleImageSize(Image srcImage)
        {
            Bitmap bmp = new Bitmap(20, 20);
            Graphics g = Graphics.FromImage(bmp);
            g.DrawImage(srcImage, new Rectangle(0, 0, bmp.Width, bmp.Height),
                        new Rectangle(0, 0, srcImage.Width, srcImage.Height),
                        GraphicsUnit.Pixel);
            g.Dispose();
            return bmp;
        }
        #endregion

        #region IMainForm members
        /// <summary>
        /// async update of status bar
        /// </summary>
        /// <param name="message"></param>
        /// <param name="percent"></param>
        public void UpdateStatus(string message, int percent)
        {
            new StatusBarUpdator(this.statusStrip1, this.bar_Status, message);
            new ProgressBarUpdator(this.statusStrip1, this.bar_Progress, percent);
        }

        /// <summary>
        /// update title
        /// </summary>
        /// <param name="title"></param>
        public void UpdateTitle(string title)
        {
            if(this.sandDockManager1.ActiveTabbedDocument !=null)
            {
                TabbedDocument tabbedDoc = (TabbedDocument) this.sandDockManager1.ActiveTabbedDocument;
                tabbedDoc.Text = title;
            }
            this.Text = string.Format("Rule Designer - {0}", title);
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsBusy
        {
            get { return isBusy; }
            set { isBusy = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public object DraggedObject
        {
            get { return draggedObject; }
            set { draggedObject = value; }
        }
        #endregion

        #region new 
        private void newToolStripButton_Click(object sender, EventArgs e)
        {
            TabbedDocument tabbedDoc = this.AddNewDesignDocument();
            RuleDocControl designCtr = new RuleDocControl();
            designCtr.OnObjectSelected += new ObjectSelected(designCtr_OnObjectSelected);
            tabbedDoc.Controls.Clear();
            tabbedDoc.Controls.Add(designCtr);
            designCtr.Dock = DockStyle.Fill;

            Rule rule = (Rule) designCtr.DesignView.Document.UserObject;
            tabbedDoc.Text = rule.RuleName;
            this._TabbedDocuments.Add(rule.RuleID, tabbedDoc);
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TabbedDocument tabbedDoc = this.AddNewDesignDocument();
            RuleDocControl designCtr = new RuleDocControl();
            designCtr.OnObjectSelected += new ObjectSelected(designCtr_OnObjectSelected);
            tabbedDoc.Controls.Clear();
            tabbedDoc.Controls.Add(designCtr);
            designCtr.Dock = DockStyle.Fill;
            Rule rule = (Rule) designCtr.DesignView.Document.UserObject;
            tabbedDoc.Text = rule.RuleName;
            this._TabbedDocuments.Add(rule.RuleID, tabbedDoc);
        }

        private TabbedDocument AddNewDesignDocument()
        {
            TD.SandDock.DocumentContainer docContainer = new TD.SandDock.DocumentContainer();
            this.Controls.Add(docContainer);


            TD.SandDock.TabbedDocument tabbedDoc =
                new TD.SandDock.TabbedDocument(this.sandDockManager1, docContainer, "New rule");
            tabbedDoc.Open();
            tabbedDoc.Closing += new TD.SandDock.DockControlClosingEventHandler(TabbedDocumentClosing);
            
            return tabbedDoc;
        }

        void designCtr_OnObjectSelected(object sender, SelectedObjectEventArgs e)
        {
            this.propertyGrid1.SelectedObject = e.SelectedObject;
        }
        #endregion

        #region close
        void TabbedDocumentClosing(object sender, TD.SandDock.DockControlClosingEventArgs e)
        {
            if (sender.GetType() == typeof(TD.SandDock.TabbedDocument))
            {
                TD.SandDock.TabbedDocument tabbedDoc = sender as TD.SandDock.TabbedDocument;
                if (tabbedDoc != null)
                {
                    RuleDocControl designCtr = tabbedDoc.Controls[0] as RuleDocControl;

                    if (designCtr != null)
                    {
                        Rule rule = designCtr.DesignView.Document.UserObject as Rule;
                        if (designCtr.IsDirty)
                        {
                            System.Windows.Forms.DialogResult continueClose =
                                MessageBox.Show("The rule is not saved, do you want to save it first?", "Close",
                                                MessageBoxButtons.YesNo);
                            if(continueClose==System.Windows.Forms.DialogResult.Yes)
                            {
                                designCtr.Save();
                            }
                        }
                        if (rule != null)
                        {
                            this._TabbedDocuments.Remove(rule.RuleID);
                            designCtr.Dispose();
                        }
                    }
                }

            }
        }
        #endregion

        #region save
        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            this.SaveRule();
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.SaveRule();
        }

        private void SaveRule()
        {
            if (this.sandDockManager1.ActiveTabbedDocument != null)
            {
                TabbedDocument doc = (TabbedDocument)this.sandDockManager1.ActiveTabbedDocument;
                RuleDocControl ruleDesignDoc = (RuleDocControl)doc.Controls[0];
                
                Rule rule = ruleDesignDoc.Save();
                doc.Text = rule.RuleName;
                TreeNode ruleTn = null;
                if (this.tree_Rules.Nodes != null)
                {
                    foreach (TreeNode ruleTreeNode in this.tree_Rules.Nodes)
                    {
                        Rule currentRule = (Rule)ruleTreeNode.Tag;
                        if (currentRule.RuleID == rule.RuleID)
                        {
                            ruleTn = ruleTreeNode;
                            ruleTn.Text = rule.RuleName;
                            ruleTn.Tag = rule;
                            break;
                        }
                    }
                }
                if (ruleTn == null)
                {
                    ruleTn = new TreeNode(rule.RuleName);
                    ruleTn.Text = rule.RuleName;
                    ruleTn.Tag = rule;
                    this.tree_Rules.Nodes.Add(ruleTn);
                }
            }
        }
        #endregion

        #region open
        private void tree_Rules_MouseDown(object sender, MouseEventArgs e)
        {
            this.tree_Rules.SelectedNode = this.tree_Rules.GetNodeAt(e.X, e.Y);
        }

        private void openToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (this.tree_Rules.SelectedNode != null)
            {
                Rule rule = (Rule) this.tree_Rules.SelectedNode.Tag;
                this.OpenRule(rule);
            }
        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            this.Open();
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Open();
        }

        private void OpenRule(Rule rule)
        {
            if(!string.IsNullOrEmpty(rule.RuleDesignFilePath))
            {
                this.OpenRuleDesignFile(rule.RuleDesignFilePath);
            }
            else
            {
                /// TODO: need to checkout the file
            }
        }

        private void Open()
        {
            OpenFileDialog dlg=new OpenFileDialog();
            dlg.Filter = "Rule files(*.rule)|*.rule|All files(*.*)|*.*";
            if(dlg.ShowDialog()==System.Windows.Forms.DialogResult.OK)
            {
                this.OpenRuleDesignFile(dlg.FileName);
            }
        }

        private void OpenRuleDesignFile(string filePath)
        {
            try
            {
                RuleDocControl ruleDesignCtr = new RuleDocControl();
                ruleDesignCtr.OpenFile(filePath);
                Rule rule = ruleDesignCtr.Rule;
                if(rule !=null)
                {
                    TabbedDocument tabbedDoc = this.AddNewDesignDocument();
                    tabbedDoc.Controls.Clear();
                    tabbedDoc.Controls.Add(ruleDesignCtr);
                    ruleDesignCtr.Dock = DockStyle.Fill;
                    tabbedDoc.Text = rule.RuleName;
                    this._TabbedDocuments.Add(rule.RuleID, tabbedDoc);
                    ruleDesignCtr.OnObjectSelected += new ObjectSelected(designCtr_OnObjectSelected);

                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
        #endregion

        #region drag-drop
        private void tree_Conditions_ItemDrag(object sender, ItemDragEventArgs e)
        {
            this.DoDragDrop(e.Item, DragDropEffects.Copy);
        }

        private void tree_Effects_ItemDrag(object sender, ItemDragEventArgs e)
        {
            this.DoDragDrop(e.Item, DragDropEffects.Copy);
        }

        private void tree_Outputs_ItemDrag(object sender, ItemDragEventArgs e)
        {
            this.DoDragDrop(e.Item, DragDropEffects.Copy);
        }

        private void tree_Actions_ItemDrag(object sender, ItemDragEventArgs e)
        {
            this.DoDragDrop(e.Item, DragDropEffects.Copy);
        }

        private void tree_Actions_MouseUp(object sender, MouseEventArgs e)
        {
            this.tree_Actions.SelectedNode = this.tree_Actions.GetNodeAt(e.X, e.Y);
            if(this.tree_Actions.SelectedNode !=null)
                this.draggedObject = this.tree_Actions.SelectedNode.Tag;
        }

        private void tree_Outputs_MouseUp(object sender, MouseEventArgs e)
        {
            this.tree_Outputs.SelectedNode = this.tree_Outputs.GetNodeAt(e.X, e.Y);
            if(this.tree_Outputs.SelectedNode !=null)
                this.draggedObject = this.tree_Outputs.SelectedNode.Tag;
        }

        private void tree_Effects_MouseUp(object sender, MouseEventArgs e)
        {
            this.tree_Effects.SelectedNode = this.tree_Effects.GetNodeAt(e.X, e.Y);
            if(this.tree_Effects.SelectedNode !=null)
                this.draggedObject = this.tree_Effects.SelectedNode.Tag;
        }

        private void tree_Conditions_MouseUp(object sender, MouseEventArgs e)
        {
            this.tree_Conditions.SelectedNode = this.tree_Conditions.GetNodeAt(e.X, e.Y);
            if(this.tree_Conditions.SelectedNode !=null)
                this.draggedObject = this.tree_Conditions.SelectedNode.Tag;
        }
        #endregion

        #region delete
        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(this.tree_Rules.SelectedNode !=null)
            {
                Rule rule = (Rule) this.tree_Rules.SelectedNode.Tag;
                System.Windows.Forms.DialogResult result =
                    MessageBox.Show("Are you sure to delete [" + rule.RuleName + "]?", "Delete",
                                    MessageBoxButtons.YesNo);
                if(result==System.Windows.Forms.DialogResult.Yes)
                {
                    ORMapping<Rule> orm=new ORMapping<Rule>();
                    orm.DeleteObjByKey(ConfigurationManager.ConnectionStrings["Workflow"].ConnectionString,
                                       rule.RuleID.ToString());
                    // RuleDALC.DeleteRule(rule.RuleID);
                    this.tree_Rules.SelectedNode.Remove();
                }
            }
        }

        #endregion

        #region print 
        private void printToolStripButton_Click(object sender, EventArgs e)
        {
            this.Print2();
        }

        private void printToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Print2();
        }

        private void Print2()
        {
            if (this.sandDockManager1.ActiveTabbedDocument != null)
            {
                TabbedDocument tabbedDoc = (TabbedDocument) this.sandDockManager1.ActiveTabbedDocument;
                RuleDocControl ruleDesignCtr = (RuleDocControl) tabbedDoc.Controls[0];
                try
                {
                    ruleDesignCtr.Save();
                    Rule rule = ruleDesignCtr.Rule;
                    this.CreateWordDocument(rule);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }

        private void CreateWordDocument(Rule rule)
        {
            object oMissing = System.Reflection.Missing.Value;
            object oEndOfDoc = "\\endofdoc"; /* \endofdoc is a predefined bookmark */

            //Start Word and create a new document.
            Microsoft.Office.Interop.Word.Application oWord;
            Microsoft.Office.Interop.Word.Document oDoc;
            oWord = new Microsoft.Office.Interop.Word.Application();
            oWord.Visible = true;
            oDoc = oWord.Documents.Add(ref oMissing, ref oMissing,
                ref oMissing, ref oMissing);

            //Insert a paragraph at the beginning of the document.
            Microsoft.Office.Interop.Word.Paragraph oPara1;
            oPara1 = oDoc.Content.Paragraphs.Add(ref oMissing);
            oPara1.Range.Text = rule.RuleName;
            oPara1.Range.Font.Bold = 1;
            oPara1.Format.SpaceAfter = 24;    //24 pt spacing after paragraph.
            oPara1.Range.InsertParagraphAfter();

            //Insert a paragraph at the end of the document.
            Microsoft.Office.Interop.Word.Paragraph oPara2;
            object oRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
            oPara2 = oDoc.Content.Paragraphs.Add(ref oRng);
            oPara2.Range.Text = "Author: " + Environment.UserName + Environment.NewLine + "Creation time: " +
                                DateTime.Now.ToString();
            oPara2.Format.SpaceAfter = 6;
            oPara2.Range.InsertParagraphAfter();

            //Insert another paragraph.
            Microsoft.Office.Interop.Word.Paragraph oPara3;
            oRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
            oPara3 = oDoc.Content.Paragraphs.Add(ref oRng);
            oPara3.Range.Text = rule.Description;
            oPara3.Range.Font.Bold = 0;
            oPara3.Format.SpaceAfter = 24;
            oPara3.Range.InsertParagraphAfter();

            //Insert a 3 x 5 table, fill it with data, and make the first row
            //bold and italic.
            Microsoft.Office.Interop.Word.Table oTable;
            Microsoft.Office.Interop.Word.Range wrdRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
            oTable =
                oDoc.Tables.Add(wrdRng, (rule.RuleNodes == null ? 1 : rule.RuleNodes.Length + 1), 3, ref oMissing,
                                ref oMissing);
            oTable.Range.ParagraphFormat.SpaceAfter = 6;
            int r, c;
            r = 1;
            oTable.Cell(1, 1).Range.Text = "Icon";
            oTable.Cell(1, 2).Range.Text = "Step";
            oTable.Cell(1, 3).Range.Text = "Description";

            if(rule.RuleNodes !=null && rule.RuleNodes.Length>0)
            {
                for (r = 0; r < rule.RuleNodes.Length; r++)
                {
                    RuleNodeDataBase ruleNodeData = rule.RuleNodes[r];
                    // Image ruleNodeIcon = ruleNodeData.Img;
                    Image ruleNodeIcon = this.ResetTransparentColor(ruleNodeData.Img, Color.White);
                    PictureWriter nodePicWriter =
                                new PictureWriter(ruleNodeIcon, ruleNodeData.Name, ruleNodeData.Description);
                    string nodePicML = nodePicWriter.ToString();
                    oTable.Cell(r + 2, 1).Range.InsertXML(nodePicML, ref oMissing);
                    oTable.Cell(r + 2, 2).Range.Text = ruleNodeData.Name;
                    oTable.Cell(r + 2, 3).Range.Text = ruleNodeData.Describe();
                }
            }
            
            oTable.Rows[1].Range.Font.Bold = 1;
            oTable.Rows[1].Range.Font.Italic = 1;

            //Add some text after the table.
            Microsoft.Office.Interop.Word.Paragraph oPara4;
            oRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
            oPara4 = oDoc.Content.Paragraphs.Add(ref oRng);
            oPara4.Range.InsertParagraphBefore();
            oPara4.Range.Text = "And here's another table:";
            oPara4.Format.SpaceAfter = 24;
            oPara4.Range.InsertParagraphAfter();

            //Insert a 5 x 2 table, fill it with data, and change the column widths.
            wrdRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
            oTable = oDoc.Tables.Add(wrdRng, 5, 2, ref oMissing, ref oMissing);
            oTable.Range.ParagraphFormat.SpaceAfter = 6;
            string strText = string.Empty;
            for (r = 1; r <= 5; r++)
                for (c = 1; c <= 2; c++)
                {
                    strText = "r" + r + "c" + c;
                    oTable.Cell(r, c).Range.Text = strText;
                }
            oTable.Columns[1].Width = oWord.InchesToPoints(2); //Change width of columns 1 & 2
            oTable.Columns[2].Width = oWord.InchesToPoints(3);

            //Keep inserting text. When you get to 7 inches from top of the
            //document, insert a hard page break.
            object oPos;
            double dPos = oWord.InchesToPoints(7);
            oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range.InsertParagraphAfter();
            do
            {
                wrdRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
                wrdRng.ParagraphFormat.SpaceAfter = 6;
                wrdRng.InsertAfter("A line of text");
                wrdRng.InsertParagraphAfter();
                oPos = wrdRng.get_Information
                               (Microsoft.Office.Interop.Word.WdInformation.wdVerticalPositionRelativeToPage);
            }
            while (dPos >= Convert.ToDouble(oPos));
            object oCollapseEnd = Microsoft.Office.Interop.Word.WdCollapseDirection.wdCollapseEnd;
            object oPageBreak = Microsoft.Office.Interop.Word.WdBreakType.wdPageBreak;
            wrdRng.Collapse(ref oCollapseEnd);
            wrdRng.InsertBreak(ref oPageBreak);
            wrdRng.Collapse(ref oCollapseEnd);
            wrdRng.InsertAfter("We're now on page 2. Here's my chart:");
            wrdRng.InsertParagraphAfter();

            //Insert a chart.
            Microsoft.Office.Interop.Word.InlineShape oShape;
            object oClassType = "MSGraph.Chart.8";
            wrdRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
            oShape = wrdRng.InlineShapes.AddOLEObject(ref oClassType, ref oMissing,
                ref oMissing, ref oMissing, ref oMissing,
                ref oMissing, ref oMissing, ref oMissing);

            //Demonstrate use of late bound oChart and oChartApp objects to
            //manipulate the chart object with MSGraph.
            object oChart;
            object oChartApp;
            oChart = oShape.OLEFormat.Object;
            oChartApp = oChart.GetType().InvokeMember("Application",
                BindingFlags.GetProperty, null, oChart, null);

            //Change the chart type to Line.
            object[] Parameters = new Object[1];
            Parameters[0] = 4; //xlLine = 4
            oChart.GetType().InvokeMember("ChartType", BindingFlags.SetProperty,
                null, oChart, Parameters);

            //Update the chart image and quit MSGraph.
            oChartApp.GetType().InvokeMember("Update",
                BindingFlags.InvokeMethod, null, oChartApp, null);
            oChartApp.GetType().InvokeMember("Quit",
                BindingFlags.InvokeMethod, null, oChartApp, null);
            //... If desired, you can proceed from here using the Microsoft Graph 
            //Object model on the oChart and oChartApp objects to make additional
            //changes to the chart.

            //Set the width of the chart.
            oShape.Width = oWord.InchesToPoints(6.25f);
            oShape.Height = oWord.InchesToPoints(3.57f);

            //Add text after the chart.
            wrdRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
            wrdRng.InsertParagraphAfter();
            wrdRng.InsertAfter("THE END.");

            //Close this form.
            // this.Close();
        }

        private void Print()
        {
            if(this.sandDockManager1.ActiveTabbedDocument !=null)
            {
                TabbedDocument tabbedDoc = (TabbedDocument) this.sandDockManager1.ActiveTabbedDocument;
                RuleDocControl ruleDesignCtr = (RuleDocControl) tabbedDoc.Controls[0];
                try
                {
                    ruleDesignCtr.Save();
                    Bitmap img = ruleDesignCtr.DesignView.GetBitmapFromCollection(ruleDesignCtr.DesignView.Document);
                    string tempFolderPath = FileUtil.GetWindowsAppFolderPath("Rules") + "\\temp";
                    if (!System.IO.Directory.Exists(tempFolderPath))
                    {
                        System.IO.Directory.CreateDirectory(tempFolderPath);
                    }
                    string dateFolderName = DateTime.Now.Year.ToString() + "-" + DateTime.Now.Month.ToString() +
                                            "-" +
                                            DateTime.Now.Day.ToString();
                    string dateFolderPath = tempFolderPath + "\\" + dateFolderName;
                    if (!System.IO.Directory.Exists(dateFolderPath))
                    {
                        System.IO.Directory.CreateDirectory(dateFolderPath);
                    }
                    string tempFileName = FileUtil.FormatFileName(ruleDesignCtr.Rule.RuleName) +
                                          ".doc";
                    string tempFilePath = System.IO.Path.Combine(tempFolderPath, tempFileName);

                    System.Text.StringBuilder buffer = new StringBuilder();
                    // create header
                    buffer.Append("<html " +
                                  "xmlns:o='urn:schemas-microsoft-com:office:office' " +
                                  "xmlns:w='urn:schemas-microsoft-com:office:word'" +
                                  "xmlns='http://www.w3.org/TR/REC-html40'>" +
                                  "<head><title>" + ruleDesignCtr.Rule.RuleName +
                                  "</title>");
                    buffer.Append("<!--[if gte mso 9]>" +
                                  "<xml>" +
                                  "<w:WordDocument>" +
                                  "<w:View>Print</w:View>" +
                                  "<w:Zoom>90</w:Zoom>" +
                                  "<w:DoNotOptimizeForBrowser/>" +
                                  "</w:WordDocument>" +
                                  "</xml>" +
                                  "<![endif]-->");
                    buffer.Append("<style>" +
                                  "<!-- /* Style Definitions */" +
                                  "@page Section1" +
                                  "   {size:8.5in 11.0in; " +
                                  "   margin:1.0in 1.25in 1.0in 1.25in ; " +
                                  "   mso-header-margin:.5in; " +
                                  "   mso-footer-margin:.5in; mso-paper-source:0;}" +
                                  " div.Section1" +
                                  "   {page:Section1;}" +
                                  "-->" +
                                  "</style></head>");

                    buffer.Append("<body lang=EN-US style='tab-interval:.5in'>" +
                                  "<div class=Section1>" +
                                  "<h1>" + ruleDesignCtr.Rule.RuleName + "</h1>");
                    //buffer.Append("<p style='color:red'><I>Create time:" +
                    //              ruleDesignCtr.Rule..ToString() + "</I></p>");
                    //buffer.Append("<p style='color:blue'><b>Author: " +
                    //              designDoc.Author + "</b></p>");

                    Rule rule = ruleDesignCtr.Document.UserObject as Rule;
                    if(rule !=null)
                    {
                        buffer.Append("<table border=\"1\">"+Environment.NewLine);
                        foreach(RuleNodeDataBase ruleNodeData in rule.RuleNodes)
                        {
                            buffer.Append("<tr>");
                            buffer.Append("<td>");
                            PictureWriter nodePicWriter =
                                new PictureWriter(ruleNodeData.Img, ruleNodeData.Name, ruleNodeData.Description);
                            string nodePicML = nodePicWriter.ToString();
                            buffer.Append(nodePicML);
                            buffer.Append("</td>");
                            buffer.Append("<td>");
                            buffer.Append(ruleNodeData.Describe());
                            buffer.Append(Environment.NewLine);
                            buffer.Append("</td>");
                            buffer.Append("</tr>");
                        }
                        buffer.Append("</table>");
                    }

                    buffer.Append("</div></body></html>" + Environment.NewLine);

                    System.IO.StreamWriter writer = new StreamWriter(tempFilePath);
                    writer.Write(buffer.ToString());
                    writer.Flush();
                    writer.Close();

                    Microsoft.Office.Interop.Word.Application app =
                        new Microsoft.Office.Interop.Word.Application();
                    app.Visible = true;
                    object missingObj = Type.Missing;
                    object filePath = tempFilePath;
                    Microsoft.Office.Interop.Word.Document doc =
                        app.Documents.Open(ref filePath, ref missingObj,
                                           ref missingObj, ref missingObj,
                                           ref missingObj, ref missingObj,
                                           ref missingObj, ref missingObj,
                                           ref missingObj, ref missingObj,
                                           ref missingObj, ref missingObj,
                                           ref missingObj, ref missingObj,
                                           ref missingObj, ref missingObj);

                    PictureWriter picWriter =
                        new PictureWriter(img, ruleDesignCtr.Rule.RuleName,
                                          ruleDesignCtr.Rule.RuleName);
                    string picML = picWriter.ToString();

                    doc.Sections.Add(ref missingObj, ref missingObj).Range.InsertXML(picML, ref missingObj);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private Image ResetTransparentColor(Image img, Color color)
        {
            if (img.PixelFormat == PixelFormat.Format32bppArgb)
            {
                Bitmap bmp = (Bitmap) img.Clone();
                BitmapData bmpData =
                    bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite,
                                 PixelFormat.Format32bppArgb);
                int stride = bmpData.Stride;
                IntPtr scan0 = bmpData.Scan0;
                unsafe
                {
                    byte* p = (byte*) (void*) scan0;
                    int offset = stride - bmp.Width*4;
                    // int width = bmp.Width*4;
                    for(int y=0;y<bmp.Height;++y)
                    {
                        for (int x = 0; x < bmp.Width; ++x)
                        {
                            int alpha = p[0];
                            if(alpha==0)
                            {
                                p[0] = color.A;
                                p[1] = color.R;
                                p[2] = color.G;
                                p[3] = color.B;
                            }
                            p += 4;
                        }
                        p += offset;
                    }
                }
                bmp.UnlockBits(bmpData);
                return bmp;
            }
            else
                return img;
        }

        //private Image RemoveImageTransparency(Image img)
        //{
        //    if(img.PixelFormat==PixelFormat.Format32bppArgb)
        //    {
        //        Image tgtImg = new Bitmap(img.Width, img.Height);
        //        Graphics g = Graphics.FromImage(tgtImg);
        //        float[][] matrixItems = new float[][]
        //            {
        //                new float[] {1, 0, 0, 0, 0},
        //                new float[] {0, 1, 0, 0, 0},
        //                new float[] {0, 0, 1, 0, 0},
        //                new float[] {0, 0, 0, 1, 0},
        //                new float[] {0, 0, 0, 0, 1}
        //            };
        //        ColorMatrix colorMatrix=new ColorMatrix(matrixItems);
        //        ImageAttributes imgAttr=new ImageAttributes();
        //        // imgAttr.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
        //        imgAttr.SetColorKey(Color.White,Color.White);
        //        g.DrawImage(img, new Rectangle(0, 0, tgtImg.Width, tgtImg.Height), 0, 0, img.Width, img.Height,
        //                    GraphicsUnit.Pixel, imgAttr);
        //        g.Dispose();
        //        return tgtImg;
        //    }
        //    else
        //        return img;
        //}
        #endregion

        #region send
        private void CreateMailMergeDataFile(ref Application wrdApp, ref Document wrdDoc)
        {
            object oMissing = System.Reflection.Missing.Value;
            object oFalse = false;

            
            Microsoft.Office.Interop.Word.Document oDataDoc;
            int iCount;

            Object oName = "C:\\DataDoc.doc";
            Object oHeader = "FirstName, LastName, Address, CityStateZip";
            wrdDoc.MailMerge.CreateDataSource(ref oName, ref oMissing,
                ref oMissing, ref oHeader, ref oMissing, ref oMissing,
                ref oMissing, ref oMissing, ref oMissing);

            // Open the file to insert data.
            oDataDoc = wrdApp.Documents.Open(ref oName, ref oMissing,
                    ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                    ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                    ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                    ref oMissing, ref oMissing);

            for (iCount = 1; iCount <= 2; iCount++)
            {
                oDataDoc.Tables[1].Rows.Add(ref oMissing);
            }
            // Fill in the data.
            FillRow(oDataDoc, 2, "Steve", "DeBroux",
                "4567 Main Street", "Buffalo, NY  98052");
            FillRow(oDataDoc, 3, "Jan", "Miksovsky",
                "1234 5th Street", "Charlotte, NC  98765");
            FillRow(oDataDoc, 4, "Brian", "Valentine",
                "12348 78th Street  Apt. 214",
                "Lubbock, TX  25874");
            // Save and close the file.
            oDataDoc.Save();
            oDataDoc.Close(ref oFalse, ref oMissing, ref oMissing);
        }

        private void FillRow(Microsoft.Office.Interop.Word.Document oDoc, int Row, string Text1, string Text2, string Text3, string Text4)
        {
            // Insert the data into the specific cell.
            oDoc.Tables[1].Cell(Row, 1).Range.InsertAfter(Text1);
            oDoc.Tables[1].Cell(Row, 2).Range.InsertAfter(Text2);
            oDoc.Tables[1].Cell(Row, 3).Range.InsertAfter(Text3);
            oDoc.Tables[1].Cell(Row, 4).Range.InsertAfter(Text4);
        }

        private void InsertLines(Application wrdApp, int LineNum)
        {
            int iCount;

            // Insert "LineNum" blank lines.	
            for (iCount = 1; iCount <= LineNum; iCount++)
            {
                wrdApp.Selection.TypeParagraph();
            }
        }

        private void shareToolStripMenuItem_Click(object sender, EventArgs e)
        {
            object oMissing = System.Reflection.Missing.Value;
            object oFalse = false;

            Microsoft.Office.Interop.Word.Selection wrdSelection;
            Microsoft.Office.Interop.Word.MailMerge wrdMailMerge;
            Microsoft.Office.Interop.Word.MailMergeFields wrdMergeFields;
            Microsoft.Office.Interop.Word.Table wrdTable;
            string StrToAdd;

            // Create an instance of Word  and make it visible.
            Application wrdApp = new Microsoft.Office.Interop.Word.Application();
            wrdApp.Visible = true;

            // Add a new document.
            Microsoft.Office.Interop.Word.Document wrdDoc = wrdApp.Documents.Add(ref oMissing, ref oMissing,
                ref oMissing, ref oMissing);
            wrdDoc.Select();

            wrdSelection = wrdApp.Selection;
            wrdMailMerge = wrdDoc.MailMerge;

            // Create a MailMerge Data file.
            this.CreateMailMergeDataFile(ref wrdApp, ref wrdDoc);

            // Create a string and insert it into the document.
            StrToAdd = "State University\r\nElectrical Engineering Department";
            wrdSelection.ParagraphFormat.Alignment =
                Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
            wrdSelection.TypeText(StrToAdd);

            InsertLines(wrdApp, 4);

            // Insert merge data.
            wrdSelection.ParagraphFormat.Alignment =
                Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphLeft;
            wrdMergeFields = wrdMailMerge.Fields;
            wrdMergeFields.Add(wrdSelection.Range, "FirstName");
            wrdSelection.TypeText(" ");
            wrdMergeFields.Add(wrdSelection.Range, "LastName");
            wrdSelection.TypeParagraph();

            wrdMergeFields.Add(wrdSelection.Range, "Address");
            wrdSelection.TypeParagraph();
            wrdMergeFields.Add(wrdSelection.Range, "CityStateZip");

            InsertLines(wrdApp, 2);

            // Right justify the line and insert a date field
            // with the current date.
            wrdSelection.ParagraphFormat.Alignment =
                Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphRight;

            Object objDate = "dddd, MMMM dd, yyyy";
            wrdSelection.InsertDateTime(ref objDate, ref oFalse, ref oMissing,
                ref oMissing, ref oMissing);

            InsertLines(wrdApp, 2);

            // Justify the rest of the document.
            wrdSelection.ParagraphFormat.Alignment =
                Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphJustify;

            wrdSelection.TypeText("Dear ");
            wrdMergeFields.Add(wrdSelection.Range, "FirstName");
            wrdSelection.TypeText(",");
            InsertLines(wrdApp, 2);

            // Create a string and insert it into the document.
            StrToAdd = "Thank you for your recent request for next " +
                "semester's class schedule for the Electrical " +
                "Engineering Department. Enclosed with this " +
                "letter is a booklet containing all the classes " +
                "offered next semester at State University.  " +
                "Several new classes will be offered in the " +
                "Electrical Engineering Department next semester.  " +
                "These classes are listed below.";
            wrdSelection.TypeText(StrToAdd);

            InsertLines(wrdApp, 2);

            // Insert a new table with 9 rows and 4 columns.
            wrdTable = wrdDoc.Tables.Add(wrdSelection.Range, 9, 4,
                ref oMissing, ref oMissing);
            // Set the column widths.
            wrdTable.Columns[1].SetWidth(51, Microsoft.Office.Interop.Word.WdRulerStyle.wdAdjustNone);
            wrdTable.Columns[2].SetWidth(170, Microsoft.Office.Interop.Word.WdRulerStyle.wdAdjustNone);
            wrdTable.Columns[3].SetWidth(100, Microsoft.Office.Interop.Word.WdRulerStyle.wdAdjustNone);
            wrdTable.Columns[4].SetWidth(111, Microsoft.Office.Interop.Word.WdRulerStyle.wdAdjustNone);
            // Set the shading on the first row to light gray.
            wrdTable.Rows[1].Cells.Shading.BackgroundPatternColorIndex =
                Microsoft.Office.Interop.Word.WdColorIndex.wdGray25;
            // Bold the first row.
            wrdTable.Rows[1].Range.Bold = 1;
            // Center the text in Cell (1,1).
            wrdTable.Cell(1, 1).Range.Paragraphs.Alignment =
                Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;

            // Fill each row of the table with data.
            FillRow(wrdDoc, 1, "Class Number", "Class Name",
                "Class Time", "Instructor");
            FillRow(wrdDoc, 2, "EE220", "Introduction to Electronics II",
                "1:00-2:00 M,W,F", "Dr. Jensen");
            FillRow(wrdDoc, 3, "EE230", "Electromagnetic Field Theory I",
                "10:00-11:30 T,T", "Dr. Crump");
            FillRow(wrdDoc, 4, "EE300", "Feedback Control Systems",
                "9:00-10:00 M,W,F", "Dr. Murdy");
            FillRow(wrdDoc, 5, "EE325", "Advanced Digital Design",
                "9:00-10:30 T,T", "Dr. Alley");
            FillRow(wrdDoc, 6, "EE350", "Advanced Communication Systems",
                "9:00-10:30 T,T", "Dr. Taylor");
            FillRow(wrdDoc, 7, "EE400", "Advanced Microwave Theory",
                "1:00-2:30 T,T", "Dr. Lee");
            FillRow(wrdDoc, 8, "EE450", "Plasma Theory",
                "1:00-2:00 M,W,F", "Dr. Davis");
            FillRow(wrdDoc, 9, "EE500", "Principles of VLSI Design",
                "3:00-4:00 M,W,F", "Dr. Ellison");

            // Go to the end of the document.
            Object oConst1 = Microsoft.Office.Interop.Word.WdGoToItem.wdGoToLine;
            Object oConst2 = Microsoft.Office.Interop.Word.WdGoToDirection.wdGoToLast;
            wrdApp.Selection.GoTo(ref oConst1, ref oConst2, ref oMissing, ref oMissing);
            InsertLines(wrdApp, 2);

            // Create a string and insert it into the document.
            StrToAdd = "For additional information regarding the " +
                "Department of Electrical Engineering, " +
                "you can visit our Web site at ";
            wrdSelection.TypeText(StrToAdd);
            // Insert a hyperlink to the Web page.
            Object oAddress = "http://www.ee.stateu.tld";
            Object oRange = wrdSelection.Range;
            wrdSelection.Hyperlinks.Add(oRange, ref oAddress, ref oMissing,
                ref oMissing, ref oMissing, ref oMissing);
            // Create a string and insert it into the document
            StrToAdd = ".  Thank you for your interest in the classes " +
                "offered in the Department of Electrical " +
                "Engineering.  If you have any other questions, " +
                "please feel free to give us a call at " +
                "555-1212.\r\n\r\n" +
                "Sincerely,\r\n\r\n" +
                "Kathryn M. Hinsch\r\n" +
                "Department of Electrical Engineering \r\n";
            wrdSelection.TypeText(StrToAdd);

            // Perform mail merge.
            wrdMailMerge.Destination = Microsoft.Office.Interop.Word.WdMailMergeDestination.wdSendToNewDocument;
            wrdMailMerge.Execute(ref oFalse);

            // Close the original form document.
            wrdDoc.Saved = true;
            wrdDoc.Close(ref oFalse, ref oMissing, ref oMissing);


            // Release References.
            wrdSelection = null;
            wrdMailMerge = null;
            wrdMergeFields = null;
            wrdDoc = null;
            wrdApp = null;

            // Clean up temp file.
            System.IO.File.Delete("C:\\DataDoc.doc");
        }
        #endregion

        private void generateCodeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(this.sandDockManager1.ActiveTabbedDocument !=null)
            {
                TabbedDocument doc = (TabbedDocument)this.sandDockManager1.ActiveTabbedDocument;
                RuleDocControl ruleDesignDoc = (RuleDocControl)doc.Controls[0];
                Rule rule = ruleDesignDoc.Save();
                try
                {
                    RuleParser parser = new RuleParser(rule);
                    SaveFileDialog dlg = new SaveFileDialog();
                    dlg.Filter = "CS files(*.cs)|*.cs|All files(*.*)|*.*";
                    if (dlg.ShowDialog() == DialogResult.OK)
                    {
                        StreamWriter writer = new StreamWriter(dlg.FileName);
                        writer.Write(parser.ClassCode);
                        writer.Flush();
                        writer.Close();
                    }
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }
    }
}
